#include <sstream>
#include <iomanip>
#include <QtDebug>
#include <QFileDialog>
#include <QMessageBox>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include "FakeJtag.h"
#include "build/ui_fakejtag.h"
#include "Emboard.h"

using namespace etb;

extern "C" void ARM9DASM(unsigned int, char *);

FakeJtag::FakeJtag(QWidget *parent) : QDialog(parent), ui(new Ui::FakeJtag), board_(NULL)
{
  ui->setupUi(this);

  connect(ui->BrowseSaveToolButton, SIGNAL(clicked()), this, SLOT(saveAct()));
  connect(ui->BrowseDownToolButton, SIGNAL(clicked()), this, SLOT(loadAct()));
  connect(ui->ProgToolButton, SIGNAL(clicked()), this, SLOT(programButton()));
  connect(ui->DumpToolButton, SIGNAL(clicked()), this, SLOT(dumpButton()));

  connect(ui->StepPushButton, SIGNAL(clicked()), this, SLOT(stepRunButton()));
  connect(ui->StopPushButton,SIGNAL(clicked()), this, SLOT(stopButton()));

  connect(ui->EraseRadioButton, SIGNAL(clicked()), this, SLOT(setProgLayout()));
  connect(ui->SdramRadioButton, SIGNAL(clicked()), this, SLOT(setProgLayout()));
  connect(ui->NorFlashRadioButton, SIGNAL(clicked()), this, SLOT(setProgLayout()));

  ui->tabWidget->setEnabled(false);
  //this->setFixedSize();
}

void FakeJtag::loadAct()
{
  QString fileName = QFileDialog::getOpenFileName(ui->BrowseDownToolButton, tr("Open File"),
                          QDir::currentPath());

  ui->FilePathLineEdit->setText(fileName);
}

void FakeJtag::saveAct()
{
  QString path = QDir::currentPath() + "/untitled.txt";
  QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
               path);

  ui->FileSaveLineEdit->setText(fileName);
  if (ui->DumpNorRadioButton->isChecked())
  {
    qDebug() << "DumpNorRadioButton";
  }

  if (ui->DumpSdramRadioButton->isChecked())
  {
     qDebug() << "DumpSdramRadioButton";
  }
  //TODO: filename write or not
  bool success = true;
  if (success)
  {

  }
  else
  {
    QMessageBox::information(this, "Error Saving File",
                 "Could not save the file");
  }
}

void FakeJtag::showCpuInfo()
{
  std::vector<U32> regs;
  board_->jtagGetCpuState(regs);

  /*
  int n = 0;
  for (std::vector<U32>::const_iterator i = regs.begin();
      i != regs.end(); i++) {
    std::cout << "R" << std::dec << n << ": 0x" << std::hex << *i << " ";
    n++;    
  }
  */

  std::ostringstream oss;

  oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << regs[0];
  ui->R0LabelValue->setText(oss.str().c_str());
  oss.str("");

  oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << regs[1];
  ui->R1LabelValue->setText(oss.str().c_str());
  oss.str("");

  oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << regs[2];
  ui->R2LabelValue->setText(oss.str().c_str());
  oss.str("");

  oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << regs[3];
  ui->R3LabelValue->setText(oss.str().c_str());
  oss.str("");

  oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << regs[4];
  ui->R4LabelValue->setText(oss.str().c_str());
  oss.str("");

  oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << regs[5];
  ui->R5LabelValue->setText(oss.str().c_str());
  oss.str("");

  oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << regs[6];
  ui->R6LabelValue->setText(oss.str().c_str());
  oss.str("");

  oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << regs[7];
  ui->R7LabelValue->setText(oss.str().c_str());
  oss.str("");

  oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << regs[8];
  ui->R8LabelValue->setText(oss.str().c_str());
  oss.str("");

  oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << regs[9];
  ui->R9LabelValue->setText(oss.str().c_str());
  oss.str("");

  oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << regs[10];
  ui->R10LabelValue->setText(oss.str().c_str());
  oss.str("");

  oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << regs[11];
  ui->R11LabelValue->setText(oss.str().c_str());
  oss.str("");

  oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << regs[12];
  ui->R12LabelValue->setText(oss.str().c_str());
  oss.str("");

  oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << regs[13];
  ui->R13LabelValue->setText(oss.str().c_str());
  oss.str("");

  oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << regs[14];
  ui->R14LabelValue->setText(oss.str().c_str());
  oss.str("");

  oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << regs[15];
  ui->R15LabelValue->setText(oss.str().c_str());
  oss.str("");

  oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << regs[16];
  ui->CPLabelValue->setText(oss.str().c_str());
  oss.str("");

  //U32 jtagGetInstruction();
  //U8 jtagGetMachineState() { return state_; }
  U32 instr = board_->jtagGetInstruction();
  //U8 status = board_->jtagGetMachineState();

  //std::cout << "machine status: " << status << std::endl;
  char str[128]={0};
  ARM9DASM(instr, str);

  std::cout << "0x" << std::hex << regs[15] << ": " <<
    "0x" << instr << " - " << str << std::endl;;

}

void FakeJtag::programButton()
{
  board_->jtagPauseMachine();
  if (ui->EraseRadioButton->isChecked())
  {
    qDebug() << "EraseRadioButton";

    ui->DownLoadProgressBar->setTextVisible(true);
    ui->DownLoadProgressBar->setRange(0, 2048);

    for (int i = 0; i < 2048; ++i) {
       U8 buf[1024];
       memset(buf, 0x0, sizeof(buf));

       board_->jtagDownloadBinary(Emboard::DOWNLOAD_TO_NOR, (U8*)buf, 1024 * i, 1024);

       ui->DownLoadProgressBar->setValue(i + 1);
     }

     QMessageBox::information(this, "Erase Info", "Erase NOR flash complete!");

     //ui->FilePathLineEdit->setVisible(true);
     //ui->BrowseDownToolButton->setVisible(true);
     //ui->FileDownLabel->setVisible(true);

  } else {
    QString fileName = ui->FilePathLineEdit->text();
    // Workaround the mingw fread bug, which is using open/read and 
    // setting the O_BINARY mode
#if defined(__MINGW__) || defined(__MINGW32__)
    int f = ::open(qPrintable(fileName), O_RDONLY | O_BINARY);
#else
    int f = ::open(qPrintable(fileName), O_RDONLY);
#endif
    if (f >= 0)
    {
      int size = 0;
      struct stat buf;
      if (::fstat(f, &buf) >= 0)
          size = buf.st_size;
      qDebug()<< "file size= " << size;

      U8 downMode = Emboard::DOWNLOAD_TO_NOR;
      if (ui->SdramRadioButton->isChecked())
        downMode = Emboard::DOWNLOAD_TO_SDRAM;
      else if (ui->NorFlashRadioButton->isChecked())
        downMode = Emboard::DOWNLOAD_TO_NOR;
      else
        downMode = Emboard::DOWNLOAD_TO_NOR;

      ui->DownLoadProgressBar->setTextVisible(true);
      ui->DownLoadProgressBar->setRange(0, size);

      int n = 0;
      int pos = 0;
      do {
        char buf[4];
        n = read(f, buf, sizeof(buf));
        //std::cout << "read size = " << n << std::endl;
        if (n > 0)
            board_->jtagDownloadBinary(downMode, (U8*)buf, pos, n);
        pos += n;
        //std::cout << "pos = " << pos << std::endl;
        ui->DownLoadProgressBar->setValue(pos);
      } while (n > 0);

      ::close(f);

      QMessageBox::information(this, "Download Info", "Download file complete!"
                               " OK to reset the board if you download to NOR"
                               " flash, otherwise binary will be executed"
                               " immediately in SDRAM.");
      if (downMode == Emboard::DOWNLOAD_TO_SDRAM) {
        board_->jtagSetPc(0x30000000);
        ui->StopPushButton->setText(tr("Run"));
        // Download to SDRAM will keep board in pause state
        return;
      } else {
        board_->jtagResetMachine();
      }
    }
    else
    {
      QMessageBox::information(this, "Error Opening File",
                   "Could not open File");
    }
  }
}

void FakeJtag::dumpButton()
{


}

void FakeJtag::stepRunButton()
{
  if (board_->jtagStepRunMachine())
    showCpuInfo();
}

void FakeJtag::stopButton()
{
  if (ui->StopPushButton->text()== tr("Pause"))
  {
    board_->jtagPauseMachine();
    showCpuInfo();
    ui->StopPushButton->setText(tr("Run"));
  }
  else if(ui->StopPushButton->text()== tr("Run"))
  {
    board_->jtagContinueMachine();
    ui->StopPushButton->setText(tr("Pause"));
  }
}

 void FakeJtag::setProgLayout()
 {
   if (ui->EraseRadioButton->isChecked())
   {
     //qDebug() << "EraseRadioButton";
     ui->FilePathLineEdit->setVisible(false);
     ui->BrowseDownToolButton->setVisible(false);
     ui->FileDownLabel->setVisible(false);
     ui->FilePathLineEdit->setText("");
   }
   else
   {
       ui->FilePathLineEdit->setVisible(true);
       ui->BrowseDownToolButton->setVisible(true);
       ui->FileDownLabel->setVisible(true);
   }
 }

 void FakeJtag::setJtagStatus(bool bLighten)
 {
     L_INFO("[FakeJtag] setJtagStatus bLighten=" << bLighten);
     if (bLighten) {
         ui->JtagStatus->setStyleSheet("background-color: rgb(0, 255, 0)");
         //ui->JtagStatus->setStyleSheet("background:green");
         ui->tabWidget->setEnabled(true);
     } else {
         ui->JtagStatus->setStyleSheet("background:white");
         ui->tabWidget->setEnabled(false);
     }
 }

FakeJtag::~FakeJtag()
{
  delete ui;
}

